{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Solution Notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Problem: Given a magazine, see if a ransom note could have been written using the letters in the magazine.\n",
    "\n",
    "* [Constraints](#Constraints)\n",
    "* [Test Cases](#Test-Cases)\n",
    "* [Algorithm](#Algorithm)\n",
    "* [Code](#Code)\n",
    "* [Unit Test](#Unit-Test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Constraints\n",
    "\n",
    "* Is this case sensitive?\n",
    "    * Yes\n",
    "* Can we assume we're working with ASCII characters?\n",
    "    * Yes\n",
    "* Can we scan the entire magazine, or should we scan only when necessary?\n",
    "    * You can scan the entire magazine\n",
    "* Can we assume the inputs are valid?\n",
    "    * No\n",
    "* Can we assume this fits memory?\n",
    "    * Yes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test Cases\n",
    "\n",
    "* None -> Exception\n",
    "* '', '' -> Exception\n",
    "* 'a', 'b' -> False\n",
    "* 'aa', 'ab' -> False\n",
    "* 'aa', 'aab' -> True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Algorithm\n",
    "\n",
    "* Build a dictionary of the magazine characters and counts.\n",
    "* Loop through each letter in the ransom note and see if there are enough letters in the magazine's dictionary.\n",
    "* Note: You could make this more efficient by not scanning the entire magazine all at once, but instead scan just in time as you run out of letters in the dictionary.\n",
    "\n",
    "Complexity:\n",
    "* Time: O(n+m), where n is the length of the ransom note and m is the length of the magazine\n",
    "* Space: O(n+m)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Solution(object):\n",
    "\n",
    "    def match_note_to_magazine(self, ransom_note, magazine):\n",
    "        if ransom_note is None or magazine is None:\n",
    "            raise TypeError('ransom_note or magazine cannot be None')\n",
    "        seen_chars = {}\n",
    "        for char in magazine:\n",
    "            if char in seen_chars:\n",
    "                seen_chars[char] += 1\n",
    "            else:\n",
    "                seen_chars[char] = 1\n",
    "        for char in ransom_note:\n",
    "            try:\n",
    "                seen_chars[char] -= 1\n",
    "            except KeyError:\n",
    "                return False\n",
    "            if seen_chars[char] < 0:\n",
    "                return False\n",
    "        return True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Unit Test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting test_ransom_note.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile test_ransom_note.py\n",
    "import unittest\n",
    "\n",
    "\n",
    "class TestRansomNote(unittest.TestCase):\n",
    "\n",
    "    def test_ransom_note(self):\n",
    "        solution = Solution()\n",
    "        self.assertRaises(TypeError, solution.match_note_to_magazine, None, None)\n",
    "        self.assertEqual(solution.match_note_to_magazine('', ''), True)\n",
    "        self.assertEqual(solution.match_note_to_magazine('a', 'b'), False)\n",
    "        self.assertEqual(solution.match_note_to_magazine('aa', 'ab'), False)\n",
    "        self.assertEqual(solution.match_note_to_magazine('aa', 'aab'), True)\n",
    "        print('Success: test_ransom_note')\n",
    "\n",
    "\n",
    "def main():\n",
    "    test = TestRansomNote()\n",
    "    test.test_ransom_note()\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success: test_ransom_note\n"
     ]
    }
   ],
   "source": [
    "%run -i test_ransom_note.py"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
